home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Multimedia & Desktop / VideoToolbox / VideoToolboxSources / FlushCacheRange.c < prev    next >
Text File  |  1995-01-05  |  8KB  |  197 lines

  1. /*
  2. FlushCacheRange.c
  3. A machine- and system-independent cache flush routine.
  4.  
  5. Beginning with the Macintosh II, developers were faced with situations where
  6. instruction and/or data caches needed to be flushed for code to execute
  7. correctly.  Unfortunately, despite recent improvements (i.e. _HWPriv, see Tech
  8. Note #261), cache flushing remains highly CPU- and system-specific and developers
  9. have had difficulty doing it in a way that ensures both forward and backward
  10. compatibility.   FlushCacheRange.c contains a single function call that will work across
  11. all platforms, yet still provides access to such advanced MC68040 features as
  12. selective cache range flushing.
  13.  
  14. Dave Radcliffe Apple DTS January, 1992
  15.  
  16. ****************************************************************************
  17. HISTORY:
  18. 7/92 dgp This routine was distributed by Apple on their Developer Disk for May, 1992.
  19. I changed the name of the file from Cache.c to FlushCacheRange.c, to match the
  20. name of the routine itself, moved the prototype from Cache.h to VideoToolbox.h,
  21. and pasted the contents of the "About..." file above. Otherwise the file is unchanged.
  22.  
  23. 5/28/94 dgp Changed the type of unimpTrapAddress from long to
  24. "UniversalProcPtr" in order to make this file compatible with Apple's Universal Headers.
  25.  
  26. 1/5/95 dgp Made compatible with Universal Headers version 2.
  27. NOTE: formerly FlushCodeCacheRange() returned an OSErr value, and FlushInstructionCache
  28. was called if FlushCodeCacheRange failed. However, Apple's version 2 Universal Headers
  29. declare FlushCodeCacheRange with no return value, so we can't check to see if it
  30. failed. I haven't looked into Apple's documentation to see if there's another way
  31. to check for failure. 
  32.  
  33. ****************************************************************************
  34.  *
  35.  *    Cache control is a highly CPU specific function.  Although some system independence
  36.  *    is achieved via use of the _HWPriv trap, this solution may not be general for all
  37.  *    hardware/system software combinations.  FlushCacheRange should solve that for
  38.  *    developers by working on all systems.
  39.  *    
  40.  *    Written by:    Dave Radcliffe
  41.  *
  42.  *    Copyright:    © 1991 by Apple Computer, Inc., all rights reserved.
  43.  *
  44.  *    Change History:
  45.  *
  46.  *        1/20/92        DR        Added System603OrLater conditional code
  47.  *        1/10/92        DR        Added FlushCacheWithCPushA()
  48.  *        12/18/91    DR        New today
  49.  *
  50.  */
  51. #if __powerc
  52.     #error "This file cannot yet be compiled as PowerPC native code."
  53. #else
  54.  
  55. #include "VideoToolbox.h"    /* for prototype of FlushCacheRange */
  56.  
  57. #ifndef __TYPES__
  58. #include <Types.h>
  59. #endif
  60.  
  61. #ifndef __TRAPS__
  62. #include <Traps.h>
  63. #endif
  64.  
  65. #ifndef __OSUTILS__
  66. #include <OSUtils.h>
  67. #endif
  68.  
  69. #ifndef __GESTALTEQU__
  70. #include <GestaltEqu.h>
  71. #endif
  72.  
  73. #ifndef __ERRORS__
  74. #include <Errors.h>
  75. #endif
  76.  
  77. /*
  78.  * If you can guarantee you are running on System 6.0.3 or later, then some of the
  79.  * alternative cache flushing code implemented below is unnecessary as you are
  80.  * assured of having the _HWPriv trap.  So, if you are running on System 6.0.3 or
  81.  * later, uncommenting the following line can reduce this code by more than half.
  82.  */
  83. /* #define System603OrLater */
  84.  
  85. /* The next two declarations are defined in Tech Note #261 */
  86. #if !defined(_CacheFlush)
  87.     #define _CacheFlush 0xA0BD
  88. #endif
  89.  
  90. #if UNIVERSAL_HEADERS<2
  91. // changed by dgp to conform to Universal Headers version 2.
  92.     #pragma parameter FlushCodeCacheRange(__A0,__A1)
  93.     pascal void FlushCodeCacheRange (void *address, unsigned long count) =
  94.         {0x7009, 0xA098};
  95.     void FlushCodeCache (void) = _CacheFlush;
  96. #endif
  97.  
  98. /* 
  99.  * FlushCacheViaCACR is an inline assembly routine that flushes both the 
  100.  * instruction and data caches by writing directly to the CACR.  Used only
  101.  * as a last resort by FlushCacheRange
  102.  */
  103. void FlushCacheViaCACR ( void ) =
  104.     { 0x4E7A, 0x0002,        /* MOVEC    CACR,D0 */
  105.       0x08C0, 0x0003,        /* BSET        #3,D0   */
  106.       0x4E7B, 0x0002 };        /* MOVEC    D0,CACR */
  107.  
  108. /*
  109.  * FlushCacheWithCPushA is another inline assembly routine that flushes caches
  110.  * on the MC68040 using the CPushA instruction.  Used only as a last resort
  111.  * by FlushCacheRange
  112.  */
  113. void FlushCacheWithCPushA ( void ) =
  114.     { 0x4E71,                /* NOP, to clear pending writes */
  115.       0xF4F8 };                /* CPUSHA    BC */
  116.       
  117. /*
  118.  * FlushCacheRange flushes both the data and instruction caches for the block of 
  119.  * memory starting at location address with size count.  Flushing the cache for 
  120.  * a range of memory is only supported on the 68040, so if this functionality is
  121.  * unavailable, the entire cache is flushed (if appropriate).
  122.  *
  123.  * If either address is NIL or count is zero, the entire cache is flushed anyway.
  124.  * Selective flushing of the cache is a time consuming process and you may wish to
  125.  * avoid it when there is no benefit to doing so.  For example, if you've recently
  126.  * manipulated a block larger than 4K (the size of the 68040 caches), selective
  127.  * flushing will probably end up flushing the entire cache anyway, so why bother?
  128.  *
  129.  * The preferred method for flushing the cache is to use the _HWPriv trap documented
  130.  * in Tech Note #261.  Some older systems may not have this trap implemented, so
  131.  * alternate methods must be used.  The first thing to try is the _CacheFlush trap.
  132.  * This was implemented beginning with the Mac II (and is also documented in Tech
  133.  * Note #261).
  134.  *
  135.  * MC68000 based systems have no cache, but if an accelerator board has been added.
  136.  * they may have a CPU which does have a cache.  Accelerator board vendors should
  137.  * implement _HWPriv or _CacheFlush for such systems, but if they haven't then
  138.  * our last resort is to control the caches directly (using privileged
  139.  * instructions (GAK!!)).
  140.  *
  141.  * FINALLY, the full implementation of FlushCacheRange is probably overkill and may be 
  142.  * less than optimal for some applications.  For example, testing for _HWPriv 
  143.  * should be unnecessary on systems later than 6.0.2, so I've added conditional code
  144.  * to allow you to bypass that if appropriate (see comment above on System603OrLater).
  145.  * The full implementation tries to cover a lot of obscure cases, but it also does 
  146.  * some things inefficiently.  For example, having determined that _HWPriv is 
  147.  * implemented, it would be more efficient to just keep that information around, 
  148.  * but I wanted to avoid the complications of global or static variables.  But 
  149.  * it is also true that if you find it necessary to call this code more than a
  150.  * few times between the time your application starts and the time it quits, 
  151.  * YOU ARE DOING SOMETHING WRONG!!   Go back and rethink your code.
  152.  */
  153. void FlushCacheRange (void *address, unsigned long count)
  154. {
  155. #ifndef System603OrLater
  156.     long    gestaltResponse;            /* For CPU type */
  157.     #if defined(USESROUTINEDESCRIPTORS)
  158.         UniversalProcPtr unimpTrapAddress;    /* Address of Unimplemented Trap */
  159.     #else
  160.         long unimpTrapAddress;            /* Address of Unimplemented Trap */
  161.     #endif    
  162.  
  163.     /* First check to see if _HWPriv is implemented */
  164.     if ((unimpTrapAddress = NGetTrapAddress(_Unimplemented, ToolTrap)) != 
  165.         NGetTrapAddress(_HWPriv, OSTrap)) {
  166. #endif
  167.         /* 
  168.          * Try to flush the specified range.  If it fails or if there is no range,
  169.          * then flush the entire cache 
  170.          */
  171.         if (address==NULL || count==0)FlushInstructionCache();/* Flush entire cache */
  172.         else FlushCodeCacheRange(address,count);
  173.         /*
  174.         NOTE: formerly FlushCodeCacheRange() returned an OSErr value, and FlushInstructionCache
  175.         was called if FlushCodeCacheRange failed. However, the version 2 Universal Headers
  176.         declare FlushCodeCacheRange with no return value, so we can't check to see if it
  177.         failed. I haven't looked into Apple's documentation to see if there's another way
  178.         to check for failure. dgp 1/5/95
  179.         */
  180. #ifndef System603OrLater
  181.     } else {                /* No _HWPriv trap */
  182.         /* Try for _CacheFlush trap */
  183.         if (unimpTrapAddress != NGetTrapAddress(_CacheFlush, OSTrap))
  184.             FlushCodeCache ();
  185.         else        /* Nothing else works, so do machine specific cache control */
  186.             /* Only bother with cache control on 68020 and above */
  187.             if (!Gestalt (gestaltProcessorType, &gestaltResponse) && 
  188.                 (gestaltResponse >= gestalt68020))
  189.                     if (gestaltResponse <= gestalt68030)
  190.                         FlushCacheViaCACR ();
  191.                     else
  192.                         FlushCacheWithCPushA ();
  193.     }
  194. #endif
  195.     return;
  196. }    /* FlushCacheRange */
  197. #endif